MemoryCache Application in ASP.NET MVC
TLDR
OutputCacheAttributeis an MVC built-inActionFilterthat usesMemoryCacheby default for server-side caching.- To isolate cache based on different user permissions, you can use
VaryByCustomin conjunction withGetVaryByCustomStringinGlobal.asax. NoStoreandLocation.Nonebehave differently:NoStoreonly affects browser caching, whileLocation.Nonedisables both browser and server-side caching.- To ensure the cache is updated immediately when the database changes, you can use
SqlChangeMonitorcombined withSqlDependencyto listen for SQL Server changes. - Before using
SqlDependency, you must ensure that theService Brokerfeature is enabled in the database.
Caching Action Content with ActionFilter
OutputCacheAttribute is used to decorate Action Methods to enable caching. If not specifically configured, it uses MemoryCache for storage by default.
Key Property Descriptions
- Duration: Cache duration (in seconds).
- Location: Specifies the cache storage location (e.g.,
Server,Client,Any, etc.). - VaryByParam: Distinguishes cache versions based on parameters (e.g., QueryString or POST parameters). Setting it to
*creates a cache for all parameter combinations. - CacheProfile: References a cache scheme defined in
Web.configfor centralized management.
TIP
Differences between NoStore and Location.None:
NoStore: Sets theCache-Controlheader tono-store, informing the browser not to cache the response; it does not affect Web Server caching behavior.Location.None: Sets theCache-Controlheader tono-cache, and the Web Server will not store any cache.
Implementation: Cache Isolation for Different Users
When to encounter this issue: When an application needs to display different content based on user permissions or identity, but the default OutputCache causes different users to receive the same cached result.
Web.config Configuration:
<system.web>
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<add name="Default" duration="30" varyByParam="*" varyByCustom="Cookie" noStore="true" />
</outputCacheProfiles>
</outputCacheSettings>
</caching>
</system.web>Global.asax.cs Implementation: Override GetVaryByCustomString to generate a unique cache key.
public override string GetVaryByCustomString(HttpContext context, string custom) {
const string OutputCacheKey = "OutputCacheId";
if (custom.Equals("Cookie", StringComparison.OrdinalIgnoreCase)) {
if (Request.Cookies[OutputCacheKey] == null) {
string cacheId = Guid.NewGuid().ToString();
Response.Cookies.Add(new HttpCookie(OutputCacheKey) {
Value = cacheId,
HttpOnly = true,
Expires = DateTime.Now.AddHours(1)
});
return cacheId;
}
return Request.Cookies[OutputCacheKey].Value;
}
return base.GetVaryByCustomString(context, custom);
}Clearing Cache Data When Updating the Database
When to encounter this issue: When the cached data source is a database, and you need to ensure that the cache is automatically invalidated or updated when the database content changes, rather than waiting for expiration.
Using SqlChangeMonitor to Monitor the Database
MemoryCache supports ChangeMonitor, where SqlChangeMonitor can listen for SQL Server change notifications via SqlDependency.
Global.asax.cs Configuration:
protected void Application_Start() {
SqlDependency.Start(WebConfigurationManager.ConnectionStrings["MyDB"].ConnectionString);
}
protected void Application_End() {
SqlDependency.Stop(WebConfigurationManager.ConnectionStrings["MyDB"].ConnectionString);
}Controller Implementation Example:
private void CreateCache() {
string connectionStr = WebConfigurationManager.ConnectionStrings["MyDB"].ConnectionString;
CacheItemPolicy policy = new CacheItemPolicy();
using (SqlConnection conn = new SqlConnection(connectionStr))
using (SqlCommand cmd = new SqlCommand("SELECT Key1 FROM dbo.Config", conn)) {
SqlDependency dependency = new SqlDependency(cmd);
dependency.OnChange += SqlDependencyOnChange;
conn.Open();
string key1 = cmd.ExecuteScalar().ToString();
SqlChangeMonitor monitor = new SqlChangeMonitor(dependency);
policy.ChangeMonitors.Add(monitor);
MemoryCache.Default.Set(CacheKey, key1, policy);
}
}WARNING
- The
Service Brokerfeature must be enabled in the database. - The SQL syntax must specify concrete columns, and the table name must include the Schema (e.g.,
dbo.TableName). - After
SqlDependencyis configured, you must execute theSqlCommandonce for the monitoring to take effect.
Enabling Service Broker
If the database is not enabled, execute:
ALTER DATABASE {DatabaseName} SET ENABLE_BROKER;If you encounter a GUID mismatch error, use the force reset command:
ALTER DATABASE {DatabaseName} SET NEW_BROKER WITH ROLLBACK IMMEDIATE;Change Log
- 2022-11-14 Initial document creation.
